#include "../Parameters.hpp"
#include "MissingOps.hpp"

using namespace BFT::order::messages;

MissingOps::MissingOps(uint32_t _view, std::vector<uint32_t> _missing_ops, uint32_t _sendingReplica)
	: BFT::messages::MacArrayMessage::MacArrayMessage(MISSING_OPS, computeSize(_missing_ops.size()),
							 _sendingReplica, BFT::Parameters::getOrderCount())
{
	viewNo = _view;
	missingOps = _missing_ops;
	
	int offset = getOffset();
	int bytes_size;
	boost::shared_ptr<char> bytes = getBytes(bytes_size);
	
	//write down the view number
	*(uint32_t*)(bytes.get()+offset) = htonl(viewNo);
	offset += VIEW_NUMBER_SIZE;
	
	//write down the number of missing ops
	*(uint16_t*)(bytes.get()+offset) = htons(missingOps.size());
	offset += OPS_COUNT_SIZE;
	
	//write down all the missing ops' sequence numbers
	for (unsigned int i=0; i < missingOps.size(); i++ )
	{
		*(uint32_t*)(bytes.get()+offset) = htonl(missingOps.at(i));
		offset += SEQUENCE_NUMBER_SIZE;
	}
	
}

MissingOps::MissingOps(boost::shared_ptr<char> _bytes, int _bytes_size)
	: BFT::messages::MacArrayMessage(_bytes, _bytes_size)
{

	if(getTag() != MISSING_OPS)
	{
		fprintf(stderr, "trying to construct a Missing ops from bytes with invalid tag\n");
		exit(172);
	}
	int offset = getOffset();
	
	//read the view number
	viewNo = ntohl( *(uint32_t*)(_bytes.get()+offset) );
	offset += VIEW_NUMBER_SIZE;
	
	//read the number of missing ops
	uint16_t ops_number;
	ops_number = ntohs( *(uint16_t*)(_bytes.get()+offset) );
	offset += OPS_COUNT_SIZE;
	
	for (unsigned int i=0; i< ops_number; i++)
	{
		missingOps.push_back( *(uint32_t*)(_bytes.get() + offset)  );
		offset += SEQUENCE_NUMBER_SIZE;
	}
	
	if((unsigned int)offset != _bytes_size - getAuthenticationSize())
	{
		fprintf(stderr, "trying to construct a MissingOps from invalid bytes\n");
		exit(171);
	}
}

bool MissingOps::equals(boost::shared_ptr<MissingOps> _other_mo)
{
	bool equal = BFT::messages::MacArrayMessage::equals(_other_mo) 
		&& viewNo == _other_mo.get()->getView() 
		&& missingOps.size() == _other_mo.get()->getMissingOps().size();
	
	for(unsigned int i=0; i< missingOps.size() && equal; i++)
	{
		equal = missingOps.at(i) == _other_mo.get()->getMissingOps().at(i);
	}	
	
	return equal;
}

uint32_t MissingOps::computeSize(unsigned int _size)
{
	return 	VIEW_NUMBER_SIZE +
	   	OPS_COUNT_SIZE +
	   	_size*SEQUENCE_NUMBER_SIZE;	
}
